AWS CloudShellでEmacsをビルドして使ってみた #reinvent
はじめに
清水です。re:Invent 2020 Werner Vogels Keynoteで発表された新サービスAWS CloudShell、リリース直後の速報エントリでyumコマンドでEmacsがインストールできることを確認しました。
ですがこのyumコマンドでのEmacsインストールには大きく2つの点が問題になる可能性があります。1つはインストール先が永続ストレージであるホームディレクトリではない点です。永続ストレージでないためCloudShellをリスタートしたり、非アクティブな状態が20分続いてセッションがタイムアウトしてしまうと、インストール先のディレクトリが初期化されてしまいます。その都度、yumコマンドでEmacsをインストールする、という方法もあるかもしれませんが、少し手間になりそうですよね。2つ目はyumコマンドでインストールできるEmacsのバージョンが最新ではない点です。先日のエントリで確認するとGNU Emacs 25.3.1
ということで極端に古いバージョンではありませんが *1、できれば最新版を使いたいところです。
ということで、AWS CloudShell上のホームディレクトリに現時点(2021/01/04)の最新版となるGNU Emacs 27.1をビルドしてみました。永続ストレージであるホームディレクトリへのインストールとなるので、リスタートやセッションタイムアウトで初期化される心配はありません。 *2 本エントリではこの手順と試行錯誤の記録をまとめてみたいと思います。
AWS CloudShellでEmacsをビルドする
CloudShellでのEmacsのビルドは以下の手順で行いました。 *3
- ビルドに必要なパッケージをyumでインストール
- 環境変数の追加(.bashrcの編集)
- Nettleをソースコードからビルドしてインストール
- GnuTLSをソースコードからビルドしてインストール
- Emacsをソースコードからビルドしてインストール
ビルドに必要なパッケージをyumでインストール
まずはEmacsとGnuTLS、そしてNettleのビルドに必要なパッケージをyumでinstallしていきます。CloudShell上で以下のコマンドを実行します。 *4
$ sudo yum install -y xz \ gcc \ m4 \ gmp-devel \ libtasn1-devel \ libunistring-devel \ unbound-devel \ p11-kit-devel \ ncurses-devel \ libxml2-devel
環境変数の追加
続いてLD_LIBRARY_PATH
とPKG_CONFIG_PATH
の2つの環境変数を追加し、共有ライブラリ検索時のパスを追加します。今回は.bashrcに記載しています。またこのタイミングでEmacsインストール先となる(バイナリファイルが保存される)$HOME/local/bin
についてもPATH
環境変数に追加しておきます。
この段階でemacsがインストールされていない想定ですので、vi
コマンドで.bashrcを開きます。
$ vi ~/.bashrc
コマンドモードでj
を連打して一番下の行に移動、o
で編集モードに入りさらに下に行を追加、 *5 以下をペーストします。
export PATH=$HOME/local/bin:$PATH export LD_LIBRARY_PATH=$HOME/local/lib64:$HOME/local/lib:/usr/lib64:$LD_LIBRARY_PATH export PKG_CONFIG_PATH=$HOME/local/lib64/pkgconfig:$HOME/local/lib/pkgconfig:/usr/lib64/pkgconfig:$PKG_CONFIG_PATH
編集が終わったらEsc
でコマンドモードに戻り、:wq
で保存して終了します。(操作でなにかミスなどしたらEsc
でコマンドモードに戻って:q!
で保存せずに終了してやり直します。) *6
保存後、再度ログインするか以下コマンドで.bashrcへの記載内容を有効にします。
$ source ~/.bashrc
Nettleをソースコードからビルドしてインストール
続いてGnuTLSをビルドする際に必要な暗号化ライブラリであるNettleをソースコードからビルドしてインストールします。インストール先はホームディレクトリ内、$HOME/local
(実際は/home/cloudshell-user/local
)とします。(以降、GnuTLSとEmacsについても同様です。)
作業用にホームディレクトリにbuild
というディレクトリを作成し、この配下のnettle
ディレクトリににソースコードファイルをダウンロード、ビルドを進めていきます。
$ cd $ mkdir build $ mkdir build/nettle $ cd build/nettle/
Nettleのソースコードは以下から、現時点(2021/01/04)の最新バージョン3.6をダウンロードしました。
$ wget https://ftp.gnu.org/gnu/nettle/nettle-3.6.tar.gz
ダウンロードしたら展開します。
$ tar xvf nettle-3.6.tar.gz
展開後に作成されたnettle-3.6
ディレクトリに移動します。
$ cd nettle-3.6
./configure
を実行しますが、オプションを2つ付与します。1つ目は--enable-mini-gmp
で、これをつけておかないと続くGnuTLSのビルド時にエラーが発生してしまいます。 *7 もう一つは--prefix=$HOME/local
で、インストール先をホームディレクトリ配下のlocal
ディレクトリとします。その他のオプションについては./configure --help
で確認が可能です。また実行ログを残しておきたいので、コマンド末尾に2>&1 | tee [ログファイル名]
も付与して実行します。
$ ./configure --enable-mini-gmp --prefix=$HOME/local 2>&1 | tee log_configure.log
続いてmake
コマンドを実行します。こちらも実行ログを残しておきたいので、コマンド末尾に2>&1 | tee [ログファイル名]
を付与します。
$ make 2>&1 | tee log_make.log
make
コマンドが完了したら、続いてmake install
します。こちらも実行ログを残しておきます。
$ make install 2>&1 | tee log_make_install.log
make install
完了後、インストール先であるホームディレクトリ配下のlocal
ディレクトリを確認すると関連するファイルが作成されていることがわかります。
GnuTLSをソースコードからビルドしてインストール
Nettleのビルドとインストールが完了したら、次はGnuTLSをソースコードからビルドしてインストールします。インストール先はNettleと同様、ホームディレクトリ内、$HOME/local
(実際は/home/cloudshell-user/local
)とします。
作業用のホームディレクトリ配下のbuild
ディレクトリにgnutls
ディレクトリを作成、このディレクトリににソースコードファイルをダウンロード、ビルドを進めていきます。
$ cd $ mkdir build/gnutls $ cd build/gnutls/
GnuTLSのソースコードは以下から、現時点(2021/01/02)の最新版のバージョン3.6.15をダウンロードしました。
- https://www.gnutls.org/download.html
- https://www.gnupg.org/ftp/gcrypt/gnutls/v3.6/gnutls-3.6.15.tar.xz
$ wget https://www.gnupg.org/ftp/gcrypt/gnutls/v3.6/gnutls-3.6.15.tar.xz
ダウンロードしたら展開します。(展開時にyumでインストールしたxz
が必要です。)
$ tar xvf gnutls-3.6.15.tar.xz
展開後に作成されたgnutls-3.6.15
ディレクトリに移動します。
$ cd gnutls-3.6.15
インストール先をホームディレクトリ配下のlocalディレクトリとするので、--prefix=$HOME/local
をつけて./configure
を実行します。実行ログを残しておきたいので、コマンド末尾に2>&1 | tee [ログファイル名]
も付与します。その他のオプションについては./configure --help
で確認が可能です。
$ ./configure --prefix=$HOME/local 2>&1 | tee log_configure.log
続いてmake
コマンドを実行します。こちらも実行ログを残しておきたいので、コマンド末尾に2>&1 | tee [ログファイル名]
を付与します。
$ make 2>&1 | tee log_make.log
make
コマンドが完了したら、続いてmake install
します。こちらも実行ログを残しておきます。
$ make install 2>&1 | tee log_make_install.log
make install
完了後、インストール先であるホームディレクトリ配下のlocalディレクトリを参照し、関連ファイルが作成されていることを確認しておきます。
Emacsをソースコードからビルドしてインストール
NettleならびにGnuTLSのビルドとインストールが終わったら、いよいよ目的であるEmacsのビルドとインストールを行います。インストール先はNettle、GnuTLSと同様、ホームディレクトリ内の$HOME/local
(実際は/home/cloudshell-user/local
)とします。そのほか、基本的に手順は他パッケージのビルド&インストールと同様です。まずはビルドするディレクトリを~/build/emacs
として作成します。
$ cd $ mkdir build/emacs $ cd build/emacs/
Emacsのソースコードは以下から、現時点(2021/01/04)での最新版である27.1をダウンロードします。
$ wget https://ftp.gnu.org/gnu/emacs/emacs-27.1.tar.xz
ダウンロードしたら展開します。
$ tar xvf emacs-27.1.tar.xz
展開後に作成されたemacs-27.1
ディレクトリに移動します。
$ cd emacs-27.1
インストール先をホームディレクトリ配下のlocal
ディレクトリとするので、--prefix=$HOME/local
をつけて./configure
を実行します。実行ログを残しておきたいので、コマンド末尾に2>&1 | tee [ログファイル名]
も付与します。その他のオプションについては./configure --help
で確認が可能です。
$ ./configure --prefix=$HOME/local 2>&1 | tee log_configure.log
続いてmake
コマンドを実行します。こちらも実行ログを残しておきたいので、コマンド末尾に2>&1 | tee [ログファイル名]
を付与します。
$ make 2>&1 | tee log_make.log
make
コマンドが完了したら、続いてmake install
します。こちらも実行ログを残しておきます。
$ make install 2>&1 | tee log_make_install.log
make install完了後、インストール先であるホームディレクトリ配下のlocalディレクトリを参照してみます。Emacs関連のファイルが作成されていますね。
すでに~/local/bin
にはパスを通しているので、任意のディレクトリでemacs
コマンドを実行してみます。
最新版のGNU Emacs 27.1
が起動しました!
セッションリスタートしてもEmacsが起動できることを確認する
ホームディレクトリに配下に最新のEmacsがインストールできました。続いて、CloudShellをリスタートさせてみて引き続きEmacsが実行できるか確認しておきましょう。右上のAction
からRestart AWS CloudShell
をクリックします。
確認のダイアログが現れますので、[Restart]でCloudShellをリスタートさせます。
しばらくして、新しいセッションでのCloudShellが実行されました。(プロンプトのIPアドレス部分が変わっていますね。)
emacs
コマンドを実行してみます。command not foundにならずEmacsが起動しましたね、やった!
ビルドに使用した不必要なファイルを削除しておく
新しいセッションのCloudShellでも、永続ストレージとなるホームディレクトリにインストールしたEmacsが実行できることが確認できました。片付けとしてビルドに使用したファイルを削除しておきましょう。なおEmacsのビルド、インストール完了した時点でdf -h
コマンドを実行すると以下のようになりました。/home
としては残り51MB、使用率95%となかなかなことになっています。なお、ビルドの試行錯誤の際、Nettleの別バージョンを入れて試していたところ、Emacsのビルド時に空き容量がなくなってディスクフルとなる事象にも遭遇しました。
ビルドは~/build
ディレクトリで行っていますので、このディレクトリをまるっと削除してしまいます。
$ rm -fr ~/build
なお、ビルドに使用したファイルを削除した段階で、ホームディレクトリの使用率は20%ほどでした。まぁ実用に耐えれる容量ではないでしょうか。(流石にビルドファイルを残しておくのは現実的でないかと思いますが。)
試行錯誤の記録
以上で最新版のEmacsをCloudShellのホームディレクトリ配下にインストール、セッション再開後も使用する、という目的は果たせました。以下にはいろいろと試行錯誤した記録をまとめておきます。
Emacsだけをソースコードからビルド
実はまず試してみたのは、Emacsだけをソースコードからビルド、他のパッケージ等はyumでインストールしてしまう方法です。xy、gccをyumでインストールした段階で./configure
を行うと以下のようにGnuTLSが足りない、ということでエラーとなります。
configure: error: The following required libraries were not found: gnutls Maybe some development libraries/packages are missing? To build anyway, give: --with-gnutls=ifavailable as options to configure.
ここでgnutls-devel
もyumでインストールしてしまいます。途中、ncurses-devel
もyumで追加でインストールすることで、./configure
、make
、make install
まで完了させることができます。
make install直後にEmacsを起動することもできますが、セッションリスタート(つまりホームディレクトリ以外のデータを初期化)したあとにEmacsを起動しようとすると、以下のようにエラーとなってしまいます。
local/bin/emacs: error while loading shared libraries: libgnutls.so.28: cannot open shared object file: No such file or directory
yumでインストールしたGnuTLSまわりのライブラリ、ホームディレクトリ以外の場所(/usr/lib
などだったかと思います)に格納されるので、初期化でファイルがなくなってしまった状態、と理解しています。ということで、このGnuTLSについてもソースコードからホームディレクトリ配下にビルドしてインストールすることとしました。
どのパッケージまでソースコードからビルドするか
GnuTLSのソースコードからのビルドの際、当初はNettleもyumでインストールする方法を試していました。しかしGnuTlSの./configure
時に以下のようにNettleが見つからない旨エラーが出てしまい、パスを通すなど試してみましたがどうにも解決できませんでした。後述しますが、GMPが必要な点も影響していたかもしれません。
configure: error: *** *** Libnettle 3.4.1 was not found.
ちょうどその時、エラーの解決に参照していたサイトが下記なのですが、他ライブラリについてもソースコードからビルドする手順が記載されていたのでyumを使わずNettleに関連するライブラリもソースコードからビルドしようか、ともちょっと思いました。ただ流石にちょと大掛かりになりすぎるかなぁ、となるべくyumを使う方法で試行錯誤していく中で、Nettleまでソースコードからのビルドでおさまった、という具合です。
なお、Nettleについては必要なライブラリ(Libtasn1、Libunistring、p11-kitなどyumでインストールしたもの)がそろっていればビルドはできたかな、という印象です。対してGnuTLSについては./configure
でエラーが出て終了してしまうことが多かったかなと。先ほどの「Libnettle 3.4.1 was not found.」のエラーのほか、NettleをインストールしていてもGMPサポートを有効にしていないと(Nettleの./configure
の際に--enable-mini-gmp
オプションを指定していないと)、以下のようなエラーが出てしまいました。ライブラリ関係のパスをきちんと通していない場合も同様です。
configure: error: *** *** Libhogweed (nettle's companion library) 3.4.1 was not found. Note that you must compile nettle with gmp support.
configure: error: *** *** gmp was not found.
yumで使われるrpmファイルをローカルにインストール
yumでインストールする際のインストール先を変更できないか、ということも少し調べてみました。yumコマンド自体では難しそうでしたが、インストールする際に使われるrpmパッケージファイルならできそう、とやってみました。
/etc/yum.conf
を編集して、rpmパッケージを保存しておくようにします。
[cloudshell-user@ip-10-0-100-182 ~]$ cat /etc/yum.conf [main] cachedir=/var/cache/yum/$basearch/$releasever keepcache=0 debuglevel=2 logfile=/var/log/yum.log exactarch=1 obsoletes=1 gpgcheck=1 plugins=1 installonly_limit=3 distroverpkg=system-release timeout=5 retries=7
試しにGnuTLSのrpmパッケージファイル、「gnutls-devel-3.3.29-9.amzn2.x86_64.rpm」をprefix指定してインストールしようとしてみましたが、not relocatableとエラーとなってしまいました。これからrpmファイルをローカル(ホームディレクトリ)にインストールする作戦は断念しました。
[cloudshell-user@ip-10-0-100-182 packages]$ rpm -ivh --prefix=$HOME/local gnutls-devel-3.3.29-9.amzn2.x86_64.rpm error: package gnutls-devel is not relocatable [cloudshell-user@ip-10-0-100-182 packages]$ rpm -qpi gnutls-devel-3.3.29-9.amzn2.x86_64.rpm Name : gnutls-devel Version : 3.3.29 Release : 9.amzn2 Architecture: x86_64 Install Date: (not installed) Group : Development/Libraries Size : 1502311 License : GPLv3+ and LGPLv2+ Signature : RSA/SHA256, Mon 24 Jun 2019 11:07:08 PM UTC, Key ID 11cf1f95c87f5b1a Source RPM : gnutls-3.3.29-9.amzn2.src.rpm Build Date : Tue 11 Jun 2019 10:57:38 AM UTC Build Host : build.amazon.com Relocations : (not relocatable) Packager : Amazon Linux Vendor : Amazon Linux URL : http://www.gnutls.org/ Summary : Development files for the gnutls package Description : GnuTLS is a secure communications library implementing the SSL, TLS and DTLS protocols and technologies around them. It provides a simple C language application programming interface (API) to access the secure communications protocols as well as APIs to parse and write X.509, PKCS #12, OpenPGP and other required structures. This package contains files needed for developing applications with the GnuTLS library.
まとめ
AWS CloudShell上で最新版のEmacsをソースコードからビルドして、永続ストレージであるホームディレクトリ配下にインストールしてみました。Emacs自体に加え、GnuTLSとさらにNettleをビルドしてインストールしておくこと、また環境変数を追加してライブラリへのパスを通しておくところがミソでした。これでリスタートやセッションタイムアウトでCloudShell環境が初期化されても、最新版のEmacsが引き続き使用可能です。ただしインストール先の永続ストレージについても120日間使用してないと削除される、という制限もありますので、こちらの対策も考えておきたいところだなと思いました。(その都度、ビルドするでも良さそうですが。)いずれにせよ、AWS CloudShell上でのより快適なEmacs環境にまた一歩近付いたかと思います。Happy Hacking with Emacs!
脚注
- 例えばmacOS 10.14 MojaveまでデフォルトでインストールされていたEmacsは22.1.1と非常に古いバージョンでした。 ↩
- ただし、ホームディレクトリの保存期間は最終セッションから120日となっているので、こちらには注意する必要があります。AWS CloudShell のホームディレクトリの保存期間に関する注意事項 #reinvent | Developers.IO ↩
- 試行錯誤の末、この手順でビルドができました。 ↩
- 厳密にはlibxml2-develはyumでインストールしない状態でもEmacsのビルドは可能でした。ただEmacs上でEWWを実行した際にlibxml2まわりエラーが出たため、インストールしています。 ↩
- viの基本的な操作を記載しているのは個人的な備忘録を兼ねています。いつもi以外で編集モードに入る方法は忘れてしまう…… ↩
- これも私がviの操作に慣れていないための備忘録です。困ったらとりあえず保存せずに終了してます。 ↩
- /.configure時に`Libhogweed (nettle's companion library) 3.4.1 was not found. Note that you must compile nettle with gmp support.`となりエラーとなります。 ↩